<script setup>
  import { ref, computed } from 'vue';
  import GridList from '../list/GridList.vue';
  import {} from 'ant-design-vue';
  import { debounce } from 'lodash';
  import useModelValue from '@/utils/useModelValue';
  const props = defineProps({
    mode: {
      type: String,
      default: 'multiple',
    },
    value: {
      type: [Array, String, Number],
      default(rawProps) {
        if (rawProps.mode === 'multiple' || !rawProps.mode) {
          return undefined;
        } else {
          return undefined;
        }
      },
    },
    column: {
      type: Number,
      default: 8,
    },
    placeholder: {
      type: String,
      default: '选择图标，输入文字搜索...',
    },
    options: {
      type: [Array, Array],
      default: [],
    },
  });
  const emit = defineEmits();
  // 分页
  const pageBase = {
    pageSize: props.column * 5,
    hideOnSinglePage: true,
    showSizeChanger: false,
    size: 'small',
  };
  const visible = ref(false);
  const isMultiple = computed(() => props.mode === 'multiple');
  /**
   * 格式化分组
   */
  const groupList = computed(() => {
    if (props.options.length === 0 || props.options[0].title !== undefined) {
      return props.options.map((group) => ({
        ...group,
        _current: ref(1),
        _searchList: group.list,
      }));
    }
    return [
      {
        title: '全部图标',
        key: '__dft',
        list: props.options,
        _current: ref(1),
        _searchList: [...props.options],
      },
    ];
  });
  /**
   * icon 字典 (方便搜索和查找)
   */
  const iconMap = computed(() => {
    const map = new Map();
    groupList.value
      .flatMap((group) => group.list)
      .forEach((item) => {
        map.set(item.value, item);
      });
    return map;
  });
  const { value: select } = useModelValue(
    () =>
      Array.isArray(props.value) || props.value === undefined
        ? props.value
        : [props.value],
    (val) => emit('update:value', isMultiple.value ? val : val?.[0])
  );
  /**
   * 选中图标
   * @param icon
   */
  function onSelect(icon) {
    const index = select.value?.indexOf(icon.value) ?? -1;
    if (index === -1) {
      select.value = isMultiple.value
        ? [...(select.value ?? []), icon.value]
        : [icon.value];
    } else if (isMultiple.value) {
      remove(icon.value);
    }
    if (!isMultiple.value) {
      visible.value = false;
    }
    searchValue.value = '';
    searchIcon('');
  }
  /**
   * 移除选中
   * @param icon
   */
  function remove(iconKey) {
    const index = select.value?.findIndex((icon) => icon === iconKey) ?? -1;
    if (index >= 0) {
      select.value = select.value?.filter((icon) => icon !== iconKey);
    }
  }
  /**
   * 搜索图标
   * @param keyword
   */
  function searchIcon(keyword) {
    const empty = keyword === '';
    const group = groupList.value.find((item) => item.key === active.value);
    const reg = new RegExp(keyword.toLowerCase());
    const filterIcon = (reg, list) => {
      return list.filter((icon) => reg.test(icon.label.toLocaleLowerCase()));
    };
    group._searchList = empty ? [...group.list] : filterIcon(reg, group.list);
    setTimeout(() => {
      groupList.value
        .filter((item) => item !== group)
        .forEach((g) => {
          g._searchList = empty ? [...g.list] : filterIcon(reg, g.list);
        });
    });
    loading.value = false;
  }
  /**
   * 搜索防抖
   */
  const _search = debounce(searchIcon, 300);
  /**
   * 搜索监听
   * @param value
   */
  function onSearch(value) {
    searchValue.value = value;
    loading.value = true;
    _search(value);
  }
  // 当前激活分组
  const active = ref(groupList.value[0]?.key);
  // 搜索关键字
  const searchValue = ref('');
  const loading = ref(false);
  function selected(icon) {
    return select.value?.includes(icon.value);
  }
</script>
<template>
  <a-select
    @click="() => (visible = true)"
    :showSearch="true"
    mode="multiple"
    v-model:value="select"
    :open="visible"
    @blur="() => (visible = false)"
    @search="onSearch"
    :searchValue="searchValue"
    v-bind="{ placeholder }"
    allow-clear
  >
    <template #dropdownRender>
      <a-spin tip="搜索中..." :spinning="loading">
        <a-tabs
          v-model:activeKey="active"
          :class="[
            'icon-selector',
            'px-base',
            'pb-base',
            {
              'no-group pt-[12px]':
                groupList.length === 1 && groupList[0].key === '__dft',
            },
          ]"
          @mousedown.prevent
        >
          <a-tab-pane :key="group.key" v-for="group in groupList">
            <template #tab>
              <a-badge
                :class="{ 'text-primary-500': active === group.key }"
                :count="
                  group._searchList.length === group.list.length
                    ? undefined
                    : group._searchList.length
                "
                showZero
              >
                {{ group.title }}
              </a-badge>
            </template>
            <GridList
              class="icon-container"
              :dataSource="group._searchList"
              :column="column"
              :pagination="{
                ...pageBase,
                current: group._current.value,
                'onUpdate:current': (val) => (group._current.value = val),
              }"
            >
              <template #renderItem="{ item }">
                <div
                  @click="onSelect(item)"
                  :class="`icon-item bg-container cursor-pointer h-10 w-10 flex justify-center items-center ${
                    selected(item) ? 'bg-primary-100' : ''
                  }`"
                >
                  <component class="icon transition" :is="item.component" />
                </div>
              </template>
            </GridList>
          </a-tab-pane>
        </a-tabs>
      </a-spin>
    </template>
    <template #tagRender="item">
      <div
        class="mx-0.5 bg-bg-disabled p-1 rounded-sm flex items-center cursor-pointer"
      >
        <component :is="iconMap.get(item.value)?.component" />
        <CloseOutlined
          v-if="isMultiple"
          class="text-subtext text-[10px] ml-1 hover:text-text"
          @click="remove(item.value)"
        />
      </div>
    </template>
  </a-select>
</template>
<style lang="less" scoped>
  .icon-selector {
    :deep(.icon-container) {
      @apply p-2 text-xl grid gap-2 bg-layout rounded;

      .icon-item {
        @apply rounded-sm border border-solid border-transparent;

        &:hover {
          @apply border-primary-500;

          .icon {
            @apply scale-125;
          }
        }
      }
    }

    &.no-group {
      :deep(.ant-tabs-nav) {
        @apply hidden;
      }
    }
  }
</style>
